//驱动具体实现
#pragma once

#include <string>
#include <vector>
#include <unordered_map>
#include <map>
#include <memory>
#include <functional>
#include "libevent_cpp/include/include_all.h"
#include "svr_util/include/singleton.h"
#include "svr_util/include/easy_code.h"
#include "svr_util/include/typedef.h"
#include "acc_driver.h"
#include "../external/rpc_libevent_cpp/src/RpcNet.h"

namespace proto {
	class ADFacadeMgr;

	//svr连接acc
	class ConToAcc : public RpcNetClient
	{
		friend class ADFacadeMgr;
		using CId2Session = std::unordered_map<uint64, Session>;

	private:
		CId2Session   m_id2sn;			 //acc cid 2 session. 用cid做key就可以了，因为来源都是一个acc。
		const uint32  m_accId = 0;	     // ConMgr::m_vec_con 索引
		bool          m_isReg = false;	 //true 表示一台 向acc 注册成功. 连接成功不代表注册成功

	public:
		ConToAcc(uint32 accId);
		bool IsReg() const { return m_isReg; };
		void OnConInitOk();
		uint32 AccId() const { return m_accId; }
		const Session *FindSession(const SessionId &id);
		const Session *FindSession(uint64 cid);
		uint32 SessionNum() { return m_id2sn.size(); };
	private:
		virtual void OnDisconnected() override;

	private:
		static void VerifyReq(uint64 cid, uint32 cmd, const std::string& msg);
		static void Forward(uint64 cid, uint32 cmd, const std::string& msg);
		static void NtfDiscon(uint64 cid);
	};

	//连接acc管理器
	class ConMgr : public Singleton<ConMgr>
	{
	private:
		std::vector< std::unique_ptr<ConToAcc> > m_vecCon;
		std::unique_ptr<AccSeting> m_seting; //如果有信息，ADClientCon连接成功会发送设置心跳信息到acc
		uint16 m_svrId = 0;
		uint16 m_mainCmd = 0; //意义同服务器组
		bool m_isVerifySvr = false;

	public:
		bool Init(const AdFacadeInitData& data);
		bool AddAcc(const AccAddr &addr);
		const std::vector<std::unique_ptr<ConToAcc>> &GetAllCon() const { return m_vecCon; };
		uint16 GetSvrId() const { return m_svrId; }
		uint16 GetMainCmd() const { return m_mainCmd; }
		bool IsVerify() const { return m_isVerifySvr; }
		ConToAcc *FindConToAcc(const SessionId &id) const;
		const Session *FindSession(const SessionId &id) const;
		void SetAccSeting(const AccSeting &seting);
		const AccSeting *GetMsgAccSeting() const { return m_seting.get(); }
		uint32 SessionNum(); //会话总数

	private:
		bool AddAcc(const char* ip, uint16 port);
	};
}